<template>
  <div
      class="org-chart-node"
      @contextmenu="$event => this.handleContextMenu($event)"
      v-if="node.visible"
      :class="{
      collapsed: !node.leftExpanded || !node.expanded,
      'is-leaf': isLeaf,
      'is-current': node.isCurrent,
      'is-left-child-node': isLeftChildNode,
      'is-not-child': node.level === 1 && node.childNodes.length <= 0 && leftChildNodes.length <= 0,
      'only-both-tree-node': node.level === 1 && tree.store.onlyBothTree
    }"
  >
    <transition :duration="animateDuration" :name="animateName">
      <div
          class="org-chart-node-left-children"
          v-if="showLeftChildNode"
          v-show="node.leftExpanded"
      >
        <OrgTreeNode
            ref="orgTreeNode"
            v-for="child in leftChildNodes"
            :show-collapsable="showCollapsable"
            :node="child"
            :label-width="labelWidth"
            :label-height="labelHeight"
            :renderContent="renderContent"
            :nodeBtnContent="nodeBtnContent"
            :selected-key="selectedKey"
            :node-key="nodeKey"
            :key="getNodeKey(child)"
            :props="props"
            :show-node-num="showNodeNum"
            is-left-child-node
        ></OrgTreeNode>
      </div>
    </transition>


    <div class="org-chart-node-label"
         :class="{
        'is-root-label': node.level === 1,
        'is-not-right-child': node.level === 1 && node.childNodes.length <= 0,
        'is-not-left-child': node.level === 1 && leftChildNodes.length <= 0
      }"
    >
      <div
          v-if="showNodeLeftBtn && leftChildNodes.length > 0"
          class="org-chart-node-left-btn"
          :class="{ expanded: node.leftExpanded }"
          @click="handleBtnClick('left')">
        <template v-if="showNodeNum">
          <span v-if="!node.leftExpanded" class="org-chart-node-btn-text">
            {{ (node.level === 1 && leftChildNodes.length > 0) ? leftChildNodes.length : node.childNodes.length }}
          </span>
        </template>
        <node-btn-content v-else :node="node">
          <slot>
          </slot>
        </node-btn-content>
      </div>
      <template v-if="node.type === 0">
        <span :class="node.status === 0 ? 'tree-node-circle tree-node-circle-disabled' : 'tree-node-circle'"
              style="margin-left: 4px;"></span>
      </template>
      <div
          @click="handleNodeClick"
          :class="computeLabelClass"
          :style="computeLabelStyle"
      >
        <template v-if="node.icon && node.icon.length > 0">
          <Tooltip v-if="!isCheckUrl(node.icon)" :content="node.icon" placement="top-start" :transfer="true">
            <Icon type="ios-apps" class="mr-5 icon" style="vertical-align: middle;"/>
          </Tooltip>
          <img :src="node.icon" v-else class="icon-img mr-5"/>
        </template>

        <node-content :node="node">
          <slot>
            <Tooltip :content="node.name" placement="top-start" :transfer="true">
              <span v-if="isEllipsis" :title="node.name" class="tree-node-name">{{ node.name | ellipsisFun(ellipsisLength) }}</span>
              <span :title="node.name" class="tree-node-name" v-else>{{ node.name }}</span>
            </Tooltip>
          </slot>
        </node-content>
        <template v-for="(info, key) in node.tags" :index="key">
          <Tooltip :content="info.description" placement="top-start">
                <span :title="info.description" class="m-l-xs layui-badge" style="margin: 0px 5px;">{{
                    info.name
                  }}</span>
          </Tooltip>
        </template>
      </div>
      <span class="layui-badge layui-bg-black mr-5 relation" v-if="isRelation && node.isRelation" @click="handleRelationNodeClick">动</span>
      <span class="layui-badge mr-5 relation-count" @click="handleRelationClassRelationNodeClick" v-if="node.selectedCount && node.selectedCount > 0">{{ node.selectedCount }}</span>
      <div
          v-if="showNodeBtn && !isLeftChildNode"
          class="org-chart-node-btn"
          :class="{ expanded: node.expanded }"
          @click="handleBtnClick('right')">
        <template v-if="showNodeNum">
          <span v-if="!node.expanded " class="org-chart-node-btn-text">
            {{ node.childNodes.length }}
          </span>
        </template>
        <node-btn-content v-else :node="node">
          <slot>
            <!--             <div class="org-chart-node-btn-text">10</div>-->
          </slot>
        </node-btn-content>
      </div>
    </div>

    <transition :duration="animateDuration" :name="animateName">
      <div
          class="org-chart-node-children"
          v-if="!isLeftChildNode && node.childNodes && node.childNodes.length > 0"
          v-show="node.expanded"
      >
        <draggable v-model="node.childNodes" delay="500" :disabled="isDraggable" handle=".org-chart-node"
                   animation="600"
                   force-fallback="true"
                   @end="handleNodeMove($event, node)">
          <template class="node">
            <OrgTreeNode
                ref="orgTreeNode"
                v-for="child in node.childNodes"
                :show-collapsable="showCollapsable"
                :node="child"
                :label-width="labelWidth"
                :label-height="labelHeight"
                :renderContent="renderContent"
                :nodeBtnContent="nodeBtnContent"
                :selected-key="selectedKey"
                :node-key="nodeKey"
                :key="getNodeKey(child)"
                :show-node-num='showNodeNum'
                :props="props"
            ></OrgTreeNode>
          </template>
        </draggable>
      </div>
    </transition>
  </div>
</template>
<script>
import {getNodeKey} from "./model/util";
import draggable from 'vuedraggable'

export default {
  name: "OrgTreeNode",
  inject: ["orgEventBus"],
  props: {
    props: {},
    node: {
      default() {
        return {};
      }
    },
    root: {
      default() {
        return {};
      }
    },
    // 子节点是否可折叠
    showCollapsable: {
      type: Boolean,
      default: false
    },
    // 判断是否是左子树的节点，样式需要改
    isLeftChildNode: {
      type: Boolean,
      default: false
    },
    // 树节点的内容区的渲染 Function
    renderContent: Function,
    // 展开节点的内容渲染 Function
    nodeBtnContent: Function,
    // 显示节点数
    showNodeNum: Boolean,
    // 树节点区域的宽度
    labelWidth: [String, Number],
    // 树节点区域的高度
    labelHeight: [String, Number],
    // 用来控制选择节点的字段名
    selectedKey: String,
    // 每个树节点用来作为唯一标识的属性，整棵树应该是唯一的
    nodeKey: String
  },
  components: {
    draggable,
    NodeContent: {
      props: {
        node: {
          required: true
        }
      },
      render(h) {
        const parent = this.$parent;
        if (parent._props.renderContent) {
          return parent._props.renderContent(h, this.node);
        } else {
          return this.$scopedSlots.default(this.node);
        }
      }
    },
    // 渲染展开节点的样式
    NodeBtnContent: {
      props: {
        node: {
          required: true
        }
      },
      render(h) {
        const parent = this.$parent;
        if (parent._props.nodeBtnContent) {
          return parent._props.nodeBtnContent(h, this.node);
        } else {
          if (this.$scopedSlots.default) {
            return this.$scopedSlots.default(this.node);
          }
        }
      }
    }
  },
  computed: {
    isLeaf() {
      if (this.node.level === 1) {
        if (this.leftChildNodes.length === 0 && this.node.childNodes.length === 0) {
          return true
        } else {
          return false
        }
      } else {
        return this.node.isLeaf
      }
    },
    leftChildNodes() {
      if (this.tree.store.onlyBothTree) {
        if (this.isLeftChildNode) {
          return this.node.childNodes;
        } else {
          return this.node.leftChildNodes;
        }
      }
      return [];
    },
    animateName() {
      if (this.tree.store.animate) {
        return this.tree.store.animateName;
      }
      return "";
    },
    animateDuration() {
      if (this.tree.store.animate) {
        return this.tree.store.animateDuration;
      }
      return 0;
    },
    isEllipsis() {
      return this.tree.store.ellipsis
    },
    ellipsisLength() {
      return this.tree.store.ellipsisLength
    },
    isRelation() {
      return this.tree.store.relation
    },
    // 是否显示展开按钮
    showNodeBtn() {
      if (this.isLeftChildNode) {
        return (
            (this.tree.store.direction === "horizontal" &&
                this.showCollapsable &&
                this.leftChildNodes.length > 0) || this.level === 1
        );
      }
      return (
          this.showCollapsable &&
          this.node.childNodes &&
          this.node.childNodes.length > 0
      )
    },
    showNodeLeftBtn() {
      return (
          (this.tree.store.direction === "horizontal" &&
              this.showCollapsable &&
              this.leftChildNodes.length > 0)
      )
    },
    // 节点的宽度
    computeLabelStyle() {
      let {labelWidth = "auto", labelHeight = "auto"} = this;
      if (typeof labelWidth === "number") {
        labelWidth = `${labelWidth}px`;
      }
      if (typeof labelHeight === "number") {
        labelHeight = `${labelHeight}px`;
      }
      return {
        width: labelWidth,
        height: labelHeight
      };
    },
    computeLabelClass() {
      // TODO 基本样式 org-chart-node-label-inner
      let clsArr = [];
      const store = this.tree.store;
      if (this.node.type === undefined || this.node.type === 0 || this.node.type === 1) {
        clsArr.push("org-chart-node-label-inner")
      } else {
        clsArr.push("org-chart-node-label-inner-text")
      }
      // TODO 有限判断是否已禁用
      if (this.node.status === 0) {
        clsArr.push("is-disabled");
      } else {
        if (store.labelClassName) {
          if (typeof store.labelClassName === "function") {
            clsArr.push(store.labelClassName(this.node));
          } else {
            clsArr.push(store.labelClassName);
          }
        }
        if (store.currentLabelClassName && this.node.isCurrent) {
          if (typeof store.currentLabelClassName === "function") {
            clsArr.push(store.currentLabelClassName(this.node));
          } else {
            clsArr.push(store.currentLabelClassName);
          }
        }
        if (this.node.isCurrent) {
          clsArr.push("is-current");
        }
        if (this.node.selected) {
          clsArr.push("label-bg-blue");
        }
      }
      return clsArr;
    },
    computeNodeStyle() {
      return {
        display: this.node.expanded ? "" : "none"
      };
    },
    computeLeftNodeStyle() {
      return {
        display: this.node.leftExpanded ? "" : "none"
      };
    },
    // 是否显示左子数
    showLeftChildNode() {
      return (
          this.tree.onlyBothTree &&
          this.tree.store.direction === "horizontal" &&
          this.leftChildNodes &&
          this.leftChildNodes.length > 0
      );
    },
    isDraggable() {
      if (this.tree.store.draggable) {
        return false
      }
      return true
    },
  },
  filters: {
    ellipsisFun(val, ellipsisLength) {
      if (!val) return ''
      if (val.length > ellipsisLength) {
        return val.slice(0, ellipsisLength) + ' ... '
      }
      return val
    }
  },
  watch: {
    "node.expanded"(val) {
      // this.$nextTick(() => this.expanded = val);
    },
    "node.leftExpanded"(val) {
      // this.$nextTick(() => this.expanded = val);
    },
  },
  data() {
    return {
      // node 的展开状态
      expanded: false,
      tree: null,
      draggable: false
    };
  },
  created() {
    let parent = this.$parent;
    if (parent.isTree === undefined && parent.tree === undefined) {
      parent = this.$parent.$parent
    }

    if (parent.isTree) {
      this.tree = parent;
    } else {
      this.tree = parent.tree;
    }
    const tree = this.tree;
    if (!tree) {
      console.warn("Can not find node's tree.");
    }
  },
  mounted() {
    //为了防止火狐浏览器拖拽的时候以新标签打开，此代码真实有效
    document.body.ondrag = function (event) {
      event.preventDefault()
      event.stopPropagation()
    }
  },
  methods: {
    getNodeKey(node) {
      return getNodeKey(this.nodeKey, node.data);
    },
    /**
     * event: 被拖拽的元素
     * data: 将停靠的对象
     * @param evt
     * @param originalEvent
     * @returns {boolean}
     */
    handleNodeMove(event, data) {
      this.tree.$emit("on-drag-drop", event, data);
      return true;
    },
    handleNodeClick() {
      const store = this.tree.store;
      if (this.node.status !== 0) {
        store.setCurrentNode(this.node);
        let dataInfo = this.node.data
        let selected = dataInfo.selected
        this.$set(dataInfo, 'selected', !selected)
        if (store.multiple) {
          this.setChildrenCurrent(this.node.childNodes, !selected)
          this.setParentCurrent(this.node.parent, true)
        } else {
          if (this.node.parent) {
            // TODO 把所有上级都修改成 FALSE
            this.setParentCurrent(this.node.parent, false)
            // TODO 将所有同级修改为 FALSE
            if (this.node.parent.parent) {
              this.setChildrenCurrent(this.node.parent.parent.childNodes, false)
            }
            // TODO 将所有下级修改为 FALSE
            this.setChildrenCurrent(this.node.childNodes, false)
          } else {
            this.setChildrenCurrent(this.node.childNodes, false)
          }
        }
        this.node.isCurrent = !selected
        this.node.data.selected = !selected
        this.tree.$emit("node-click", this.node.data, this.node, this);
      }
    },
    // 关联动态资源
    handleRelationNodeClick() {
      const store = this.tree.store;
      store.setCurrentNode(this.node);
      this.tree.$emit("relation-node-click", this.node.data, this.node, this);
    },
    handleRelationClassRelationNodeClick() {
      const store = this.tree.store;
      store.setCurrentNode(this.node);
      this.tree.$emit("on-relation-count", this.node.data, this.node, this);
    },
    setChildrenCurrent(arr, isCurrent = true) {
      arr.forEach((item) => {
        item.isCurrent = isCurrent
        item.data.selected = isCurrent
        if (item.childNodes && item.childNodes.length > 0) {
          this.setChildrenCurrent(item.childNodes, isCurrent)
        }
      })
    },
    setParentCurrent(info, selected = true) {
      if (info.parent) {
        info.isCurrent = selected
        info.data.selected = selected
        this.setParentCurrent(info.parent, selected)
      }
    },
    handleBtnClick(isLeft) {
      isLeft = isLeft === "left";
      const store = this.tree.store;
      // 表示是OKR飞书模式
      if (store.onlyBothTree) {
        if (isLeft) {
          if (this.node.leftExpanded) {
            this.node.leftExpanded = false;
            this.tree.$emit("node-collapse", this.node.data, this.node, this);
          } else {
            this.node.leftExpanded = true;
            this.tree.$emit("node-expand", this.node.data, this.node, this);
          }
          return;
        }
      }
      if (this.node.expanded) {
        this.node.collapse();
        this.tree.$emit("node-collapse", this.node.data, this.node, this);
      } else {
        this.node.expand();
        this.tree.$emit("node-expand", this.node.data, this.node, this);
      }
    },
    handleContextMenu(event) {
      if (
          this.tree._events["node-contextmenu"] &&
          this.tree._events["node-contextmenu"].length > 0
      ) {
        event.stopPropagation();
        event.preventDefault();
      }
      this.tree.$emit(
          "node-contextmenu",
          event,
          this.node.data,
          this.node,
          this
      );
    },
    isCheckUrl(sUrl) {
      let bIsUrl = false
      const rUrl = new RegExp('(http|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?')
      if (sUrl !== '' && sUrl !== undefined && sUrl.match(rUrl) != null) {
        bIsUrl = true
      }
      return bIsUrl
    }
  }
};
</script>
